import { Repository, SelectQueryBuilder } from "typeorm";

import type { BIGINT_PG, ConditionList, ExtBigIdTuple, ExtIdTuple, ExtUUidTuple, INTEGER_PG, KeyAccumulatable, KeyBigInt, PageDto, PageResult } from "qqlx-core";

export interface Constructable<T> {
  new(): T;
}

export interface EntityMatch<T> {
  count: number;
  firstMatch?: T;
}

export interface DaoComAction<S extends ExtIdTuple | ExtUUidTuple | ExtBigIdTuple, Id> {
  /** 数据表名称 */
  relations_name: string;

  /** TypeORM 数据表操作对象 */
  repository: Repository<S>;

  // 模型
  getSchema(): S;

  // 查询
  verifyIdentity(identify: Id): void;
  insertOne(schema: S): Promise<S>;
  insertMany(schema: S[]): Promise<Id[]>;
  insertManyAndQuery(schema: S[]): Promise<S[]>;

  // 修改
  updateOne(id: Id, updating: Partial<S>): Promise<S>;
  updateOneSafe(id: Id, updating: Partial<S>): void;

  // 删除
  setDisableTrue(id: Id): Promise<S>;
  setDisableFalse(id: Id): Promise<S>;
  deleteOneById(id: Id): void;

  /** 查询构建器：不要复用构建器！因为条件之间会互相覆盖 */
  getQueryBuilder(): SelectQueryBuilder<S>;

  /** 整理条件列表
   * @step1 关键词不能为空
   * @step2 反转条件列表，保证最后的条件会覆盖前面的条件
   * @step3 不要重复
   */
  shakeConditionList(cs: ConditionList<S>): ConditionList<S>;

  /** 设置查询条件
   * @withSort 是否写入排序规则（默认都会写入）
   */
  setCondition(qb: SelectQueryBuilder<S>, cons: ConditionList<S>, withSort: boolean): void;

  /** 查找一条记录，找不到会报错 */
  findOneById(identify: Id): Promise<S>;
  findManyById(identifyList: Id[]): Promise<S[]>;

  /** 全量条件查询：如果没有条件，则会返回空数组 */
  queryAll(cs: ConditionList<S>, qb?: SelectQueryBuilder<S>): Promise<PageResult<S>>;

  /** 条件匹配第一条数据：如果没有条件，则会返回空 */
  queryMatch(cs: ConditionList<S>, qb?: SelectQueryBuilder<S>): Promise<EntityMatch<S>>;

  /** 分页查询：如果没有条件，则会返回空数组 */
  page(op: PageDto<S>, qb?: SelectQueryBuilder<S>): Promise<PageResult<S>>;

  /** 会去掉传入的排序条件 */
  count(cs: ConditionList<S>): Promise<number>;

  /** 目前仅仅合计类型为 Integer(32bit) 的数据 */
  sum(key: KeyAccumulatable<S>, cs: ConditionList<S>): Promise<INTEGER_PG>;
  sumBigInt(key: KeyBigInt<S>, cs: ConditionList<S>): Promise<BIGINT_PG>;
}
